#ifndef NOSAL_LOG_MANAGER_H
#define NOSAL_LOG_MANAGER_H

#include "nosal/log/common.h"
#include <map>
#include <memory>
#include <mutex>

namespace netaos {
namespace nosal {
namespace log {

class Logger;

namespace internal
{

/**
 * Class holding the main logic of the logging API.
 * It handles the de-/registration of the application against the slog2 back-end and is responsible
 * for the logger contexts object life time.
 */
class LogManager final
{
public:
    LogManager();

    /**
     * Sets the application ID, description, default log level and mode.
     * In case of an empty string for @param[in] application_id, it will be set to "XXXX".
     *
     * @param[in] application_id            The application ID
     * @param[in] description      The application description
     * @param[in] loglevel         The default application reporting log level
     * @param[in] logmode          The application log mode
     * @param[in] directory_path    The directory path for the file log mode
     *
     */
    void Initialize(std::string application_id,
        std::string description,
        LogLevel loglevel,
        LogMode logmode,
        std::string directory_path) noexcept;

    // Unregisters remaining log contexts and the application before shutting down.
    ~LogManager();

    // Disable copy and move operations
    LogManager(const LogManager&) = delete;
    LogManager(LogManager&&) = delete;
    LogManager& operator=(const LogManager&) = delete;
    LogManager& operator=(LogManager&&) = delete;

    /**
     * Creates a logger, representing a slog2 context.
     *
     * Tracks internally all created contexts and cares for their deregistration.
     * It also checks whether requested ID isn't created yet, and if so it returns the already
     * available logger as reference.
     *
     * Implementation is multi-thread safe via serialization.
     *
     * @param[in] context_id          The _up to four-character_ ID
     * @param[in] description         Some description
     * @param[in] default_loglevel    The context's default log reporting level
     * @return                        Reference to the logger object
     */
    Logger& CreateLogContext(std::string context_id,
        std::string description,
        LogLevel default_loglevel) noexcept;

    struct Deleter
    {
        void operator()(Logger* ptr) const;
    };

private:

    Logger& getInternalLogger() noexcept;

    using LoggerPtr = std::unique_ptr<Logger, LogManager::Deleter>;

    LoggerPtr internal_logger_;

    std::map<std::string, LoggerPtr> log_contexts_;

    std::mutex log_contexts_mutex_;

    std::once_flag init_internal_logger_;

    bool enable_console_;
    bool enable_remote_;
};

}  // namespace internal
}  // namespace log
}  // namespace nosal
}  // namespace netaos

#endif  // NOSAL_LOG_MANAGER_H
